import { Button, Dropdown, Input, Menu, Upload } from "antd"
import { UploadChangeParam } from "antd/es/upload/interface"
import { UploadFile } from "antd/lib/upload/interface"
import dayjs from "dayjs"
import { groupBy, mapValues } from "lodash"
import { ChangeEventHandler, useCallback, useRef, useState } from "react"
import { Helmet } from "react-helmet"
import styled from "styled-components"
import { names, subtotalLists } from "./config"
import { readCSV } from "./readWrite"

enum OperateState {
  idle,
  operate,
  done
}
enum Encodes {
  gb2312 = "gb2312",
  utf8 = "utf8"
}

export type List = {
  name: string;
  value: number;
  type: "buy" | "sell"
}[]

function toGroup(list: List) {
  const group = groupBy(list, "name")
  return mapValues(group, arr => {
    const obj = { buy: 0, sell: 0 }
    arr.forEach(ele => {
      obj[ele.type] += ele.value
    })
    return obj
  });
}

const regexp = /^([A-z]{1,4}).*$/
function getNameAbbreviation(name: string) {
  return name.replace(regexp, "$1").toUpperCase()
}

function OperationalHedgingTool() {
  const [operateState, setOperateState] = useState(OperateState.idle)
  // 操作文件
  const [selectOperateFileList, setSelectOperateFileList] = useState<UploadFile<any>[]>([])
  const [selectFundsFileList, setSelectFundsFileList] = useState<UploadFile<any>[]>([])
  const [fileName, setFileName] = useState(dayjs().format("YYYYMMDD"))
  const [operatingSteps, setOperatingSteps] = useState("")
  const [downloadData, setDownloadData] = useState("")
  const [encode, setEncode] = useState<Encodes>(Encodes.gb2312)

  const handleSelectOperateFileList = useCallback<(info: UploadChangeParam) => any>(info => {
    console.log(info);
    setSelectOperateFileList(old => {
      if (old.length > info.fileList.length) {
        // 删除
        return info.fileList
      } else if (old.findIndex(file => file.name === info.file.name) === -1) {
        // 添加新项
        setOperateState(OperateState.idle)
        return [...old, info.file]
      }
      return old
    })
  }, [])
  const handleSelectFundsFileList = useCallback<(info: UploadChangeParam) => any>(info => {
    console.log(info);
    setSelectFundsFileList(old => {
      if (old.length > info.fileList.length) {
        // 删除
        return info.fileList
      } else if (old.findIndex(file => file.name === info.file.name) === -1) {
        // 添加新项
        setOperateState(OperateState.idle)
        return [...old, info.file]
      }
      return old
    })
  }, [])
  const changeFileName = useCallback<ChangeEventHandler<HTMLInputElement>>((str) => {
    console.log(str.target.value, "-");
    setFileName(str.target.value)
  }, [])


  const handleFiles = useCallback(async () => {
    if (!fileName) {
      setOperatingSteps("文件名不能为空")
      return
    }
    if (!selectOperateFileList.length) {
      setOperatingSteps("未选择操作文件")
      return
    }
    if (!selectFundsFileList.length) {
      setOperatingSteps("未选择资金文件")
      return
    }

    setOperateState(OperateState.operate)
    const listOperate: List = []
    const listFunds: List = []
    try {
      // 遍历读取操作文件
      for (let i = 0; i < selectOperateFileList.length; i++) {
        const file = selectOperateFileList[i]
        setOperatingSteps(`读取csv文件：${file.name}`)
        const page = await readCSV(file as any, row => ({
          name: getNameAbbreviation(row[0]),
          value: parseInt(row[2]),
          type: row[1] === "买" ? "buy" : "sell"
        }))
        listOperate.push(...page)
      }
      // 遍历读取资金文件
      for (let i = 0; i < selectFundsFileList.length; i++) {
        const file = selectFundsFileList[i]
        setOperatingSteps(`读取csv文件：${file.name}`)
        const page = await readCSV(file as any, row => ({
          name: getNameAbbreviation(row[0]),
          value: parseInt(row[2]),
          type: row[1] === "买" ? "buy" : "sell"
        }))
        listFunds.push(...page)
      }
      // 将每条数据进行分组汇总
      const groupOperate = toGroup(listOperate)
      const groupFunds = toGroup(listFunds)
      console.log(groupOperate, groupFunds);

      setOperatingSteps("生成完成")
      const rows = [`品种,,操作,操作对冲,资金,资金对冲,总计`]
      // 总计
      let /* 操作 */allBlockCz = 0
      let /* 操作对冲 */allBlockCzdc = 0
      let /* 资金 */allBlockZj = 0
      let /* 资金对冲 */allBlockZjdc = 0
      let /* 总计 */allBlockCount = 0
      subtotalLists.forEach(block => {
        // 小计
        let /* 操作 */blockCz = 0
        let /* 操作对冲 */blockCzdc = 0
        let /* 资金 */blockZj = 0
        let /* 资金对冲 */blockZjdc = 0
        let /* 总计 */blockCount = 0
        block.forEach(key => {
          const operate = groupOperate[key]
          const fund = groupFunds[key]
          let /* 操作 */cz = 0
          let /* 操作对冲 */czdc = 0
          let /* 资金 */zj = 0
          let /* 资金对冲 */zjdc = 0
          let /* 总计 */count = 0
          if (operate) {
            cz = operate.buy - operate.sell
            czdc = Math.min(operate.buy, operate.sell)
          }
          if (fund) {
            zj = fund.buy - fund.sell
            zjdc = Math.min(fund.buy, fund.sell)
          }
          if (operate || fund) {
            count = cz - zj;
          }
          blockCz += cz
          blockCzdc += czdc
          blockZj += zj
          blockZjdc += zjdc
          blockCount += count
          rows.push([key, names[key], cz, czdc, zj, zjdc, count].join(","))
        })
        allBlockCz += blockCz
        allBlockCzdc += blockCzdc
        allBlockZj += blockZj
        allBlockZjdc += blockZjdc
        allBlockCount += blockCount
        rows.push(["", "小计", blockCz, blockCzdc, blockZj, blockZjdc, blockCount].join(","))
        rows.push("")
        rows.push("")
      })
      rows.push(["", "总计", allBlockCz, allBlockCzdc, allBlockZj, allBlockZjdc, allBlockCount].join(","))
      setDownloadData(`data:text/csv;charset=gb2312,\ufeff${encodeURIComponent(rows.join("\n"))}`)
      setOperateState(OperateState.done)
    } catch (error) {
      console.log(error);
      setOperatingSteps(`错误：${error}`)
    }
  }, [fileName, selectFundsFileList, selectOperateFileList])

  const menu = useRef(
    <Menu>
      <Menu.Item key={Encodes.gb2312}>
        <span onClick={() => setEncode(Encodes.gb2312)}>
          {Encodes.gb2312.toUpperCase()}
        </span>
      </Menu.Item>
      <Menu.Item key={Encodes.utf8}>
        <span onClick={() => setEncode(Encodes.utf8)}>
          {Encodes.utf8.toUpperCase()}
        </span>
      </Menu.Item>
    </Menu>
  )

  return <Container>
    <Helmet>
      <title>操作对冲</title>
    </Helmet>
    <Upload className="upload" disabled={operateState === OperateState.operate} fileList={selectOperateFileList} onChange={handleSelectOperateFileList} accept=".csv" beforeUpload={() => false} multiple>
      <Button disabled={operateState === OperateState.operate} type="primary">选择操作文件</Button>
    </Upload>
    <br />
    <Upload className="upload" disabled={operateState === OperateState.operate} fileList={selectFundsFileList} onChange={handleSelectFundsFileList} accept=".csv" beforeUpload={() => false} multiple>
      <Button disabled={operateState === OperateState.operate} type="primary">选择资金文件</Button>
    </Upload>
    <br />
    <FileMsgWrapper>
      <Input addonBefore="输出文件名" addonAfter=".csv" value={fileName} onChange={changeFileName} />
      <Dropdown overlay={menu.current}>
        <Button className="encode">{encode.toUpperCase()}</Button>
      </Dropdown>
    </FileMsgWrapper>
    <Button type="primary" loading={operateState === OperateState.operate} disabled={operateState === OperateState.operate} onClick={handleFiles}>
      {operateState === OperateState.operate ? "处理中" : "读取并计算"}
    </Button>
    <Button disabled={!(downloadData && fileName)} type="link" href={downloadData} download={`${fileName}.csv`}>下载</Button>
    <OperateMsg>{operatingSteps}</OperateMsg>
  </Container>
}

const Container = styled.div`
  padding: 15px;
  .upload {
    display: flex;
    justify-content: center;
  }
  .ant-upload-list.ant-upload-list-text {
    display: inline-flex;
    flex: 1;
    flex-wrap: wrap;
  }
`
const OperateMsg = styled.span`
  color: #999;
`

const FileMsgWrapper = styled.div`
  display: flex;
  margin-bottom: 15px;
  .ant-input-group-wrapper {
    margin-right: 15px;
    flex: none;
    width: 300px;
  }
  .encode {
    width: 100px;
    flex: none;
  }
`

export default OperationalHedgingTool